/*
 * Copyright 2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.seppiko.pigeon.services;

import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
import org.seppiko.pigeon.configuration.PigeonConfiguration;
import org.seppiko.pigeon.exceptions.MailAddressFormatException;
import org.seppiko.pigeon.exceptions.PigeonException;
import org.seppiko.pigeon.models.MailEntity;
import org.seppiko.pigeon.utils.DatetimeUtil;
import org.seppiko.pigeon.utils.JsonUtil;
import org.seppiko.pigeon.utils.MailUtil;
import org.springframework.stereotype.Service;

/**
 * @author Leonard Woo
 */
@Slf4j(topic = "mailSpy")
@Service
public class LogService {

  private final PigeonConfiguration configuration = PigeonConfiguration.getInstance();

  public void mailLogger(MailEntity mailEntity) {
    try {
      MailEntity mail = (MailEntity) deepClone(mailEntity);
      if (configuration.getHideAdd() > 0) {
        boolean hideUser = false;
        boolean hideDomain = false;
        switch (configuration.getHideAdd()) {
          case 1:
            hideUser = true;
            hideDomain = false;
            break;
          case 2:
            hideUser = false;
            hideDomain = true;
            break;
          case 3:
            hideUser = true;
            hideDomain = true;
            break;
        }
        mail.setFrom( MailUtil.hideAdd(mail.getFrom(), hideUser, hideDomain) );
        mail.setTo( MailUtil.hideAdds(mail.getTo(), hideUser, hideDomain) );
        mail.setCc( MailUtil.hideAdds(mail.getCc(), hideUser, hideDomain) );
        mail.setBcc( MailUtil.hideAdds(mail.getBcc(), hideUser, hideDomain) );
        mail.setReplayTo( MailUtil.hideAdd(mail.getReplayTo(), hideUser, hideDomain) );
      }
      ObjectNode obj = Objects.requireNonNull( JsonUtil.toJsonObject(mail) );
      if (configuration.isOnlyAdd()) {
        obj.remove("subject");
        obj.remove("text");
        obj.remove("html");
      }
      obj.put("timestamp", DatetimeUtil.now());
      String json = JsonUtil.toJson(obj);

      log.info(json);
    } catch (NullPointerException ex) {
      log.warn("Something is null", ex);
    } catch (MailAddressFormatException ex) {
      log.warn(ex.getMessage());
    } catch (PigeonException ex) {
      log.error(ex.getMessage(), ex);
    }
  }

  private static Object deepClone(Object obj) throws PigeonException{
    try {
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      ObjectOutputStream oos = new ObjectOutputStream(baos);
      oos.writeObject(obj);
      ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
      ObjectInputStream ois = new ObjectInputStream(bais);
      return ois.readObject();
    } catch (IOException | ClassNotFoundException ex) {
      throw new PigeonException("Deep copy failed", ex);
    }
  }
}
